package com.xj.community.util;

import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

@Component
public class SensitiveWordsFilter {
    private  Logger logger = LoggerFactory.getLogger(SensitiveWordsFilter.class);

    private static final String REPALCEMENT = "***";
    //前缀树的根节点
    private Trie root = new Trie();

    //根据敏感词初始化前缀树
    @PostConstruct
    public void init(){
        ClassLoader classLoader = SensitiveWordsFilter.class.getClassLoader();
        InputStream is = classLoader.getResourceAsStream("sensitiveWords.txt");
        InputStreamReader inputStreamReader = new InputStreamReader(is);
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
        try {
            String line = null;
            while((line = bufferedReader.readLine())!=null){
                addWord(line);
            }
        } catch (IOException e) {
            logger.error("加载敏感词文件失败"+e.getMessage());
        }
    }


    //将一个敏感词添加到前缀树中
    public void addWord(String s){
        int i = 0;
        Trie cur = root;
        while(i < s.length()){
            Character character = (Character) s.charAt(i);
            if(cur.search(character) != null){
                cur = cur.search(character);
            }else{
                Trie node = new Trie();
                cur.put(character,node);
                cur = node;
            }
            i++;
        }
        cur.setFlag(true);
    }

    //过滤敏感词,返回过滤后的文本
    public String filter(String text){
        if(StringUtils.isBlank(text))return null;
        StringBuilder sb = new StringBuilder();
        //三个指针变量
        //用于遍历前缀树
        Trie cur = root;
        //用于遍历字符串文本
        int begin = 0;
        int position = 0;
        while(position < text.length()){
            char c = text.charAt(position);
            //跳过特殊符号
            if(isSymbol(c)){
                //如果此时cur指向根节点,说明begin指向该特殊字符
                if(cur == root){
                    sb.append(c);//将该特殊字符纳入结果字符中
                    begin++;
                }
                position++;//跳过
                continue;
            }

            cur =  cur.search(c);
            if(cur == null){//说明beigin ~ position-1的字符不是敏感字符
//                sb.append(text.substring(begin,position-1));错误写法
                sb.append(text.charAt(begin));
                position = ++begin;
                cur = root;
            }else if(cur.getFlag()){
                sb.append(REPALCEMENT);
                begin = ++position;
                cur = root;
            }else{
                position++;
            }
        }
        //position指针先到达字符串结尾
        sb.append(text.substring(begin));
        return sb.toString();
    }

    // 判断是否为特殊符号
    private boolean isSymbol(Character c) {
        // 0x2E80~0x9FFF 是东亚文字范围
        return !CharUtils.isAsciiAlphanumeric(c) && (c < 0x2E80 || c > 0x9FFF);
    }

    //定义前缀树
    private class Trie{
        private boolean flag;//用于标记单词结束

        private Map<Character,Trie> map = new HashMap<>();//用于存储子节点

        public boolean getFlag() {
            return flag;
        }

        public void setFlag(boolean flag) {
            this.flag = flag;
        }

        //添加子节点
        public void put(Character c, Trie trie){
            map.put(c,trie);
        }

        //查找子节点
        public Trie search(Character c){
            return map.get(c);
        }

    }
}
